/*
 * Copyright (C), 2002-2017, 苏宁易购电子商务有限公司
 * FileName: LabelRemoteServiceImpl.java
 * Author:   15050536
 * Date:     2017年5月24日 下午2:06:21
 * Description: //模块目的、功能描述      
 * History: //修改记录
 * <author>      <time>      <version>    <desc>
 * 修改人姓名             修改时间            版本号                  描述
 */
package com.suning.sawp.member.service.impl;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimaps;
import com.google.gson.reflect.TypeToken;
import com.suning.rsf.provider.annotation.Implement;
import com.suning.sawp.constants.CacheKeyConstants;
import com.suning.sawp.constants.ConfigConstants;
import com.suning.sawp.constants.ErrorCodeConstants;
import com.suning.sawp.dto.common.ReturnMsg;
import com.suning.sawp.member.constant.LabelChannelEnum;
import com.suning.sawp.member.constant.MemberConstants;
import com.suning.sawp.member.dao.LabelDao;
import com.suning.sawp.member.dto.CustomerDetail;
import com.suning.sawp.member.dto.Label;
import com.suning.sawp.member.dto.MemCustomer;
import com.suning.sawp.member.service.ActivityService;
import com.suning.sawp.member.vo.MemCustomerDetailResponse;
import com.suning.sawp.remote.dto.BaseResponse;
import com.suning.sawp.remote.dto.LabelDto;
import com.suning.sawp.remote.dto.ReqLabel;
import com.suning.sawp.remote.dto.ResponseLabelInfo;
import com.suning.sawp.remote.intf.LabelRemoteService;
import com.suning.sawp.service.util.AESUtils;
import com.suning.sawp.service.util.RedisCacheUtils;

/**
 * 标签服务实现<br>
 *
 * @author 15050536 石键平
 */

@Implement(contract = LabelRemoteService.class, implCode = "labelRemoteService")
@Service
public class LabelRemoteServiceImpl implements LabelRemoteService {

	// 日志对象
	private static final Logger LOGGER = LoggerFactory.getLogger(ActivityServiceImpl.class);

	@Autowired
	private LabelDao labelDao;

	@Autowired
	private ActivityService activityService;

	@Autowired
	private RedisCacheUtils redisClient;

	@Override
	public ResponseLabelInfo queryLabelByCustNo(String custNo) {
		ResponseLabelInfo response = new ResponseLabelInfo();
		response.setRetFlag(ReturnMsg.FAIL);

		String key = CacheKeyConstants.ALL_LABELS;
		Type type = new TypeToken<List<Label>>() {
		}.getType();
		List<Label> labelList = redisClient.hget(key, LabelChannelEnum.CHANNEL_POS.getCode(), type);
		if (labelList == null) {
			// 查询pos渠道的标签
			labelList = labelDao.queryAllLabel(LabelChannelEnum.CHANNEL_POS.getCode());
			if (labelList != null) {
				// 数据入缓存
				redisClient.hsetWithMyExpireTime(key, LabelChannelEnum.CHANNEL_POS.getCode(), labelList, CacheKeyConstants.ONE_DAY_EXPIRE_TIME);
			}
		}

		if (CollectionUtils.isEmpty(labelList)) {
			response.setErrorCode(ErrorCodeConstants.ERR_MEM_0052);
			response.setErrorMessage(ErrorCodeConstants.ERR_MAP.get(ErrorCodeConstants.ERR_MEM_0052));
			return response;
		}
		dealLabelList(response, labelList);

		response.setRetFlag(ReturnMsg.SUCCESS);
		return response;
	}

	/**
	 * 
	 * 把查询到的所有标签，按照必填和选填分组<br/>
	 * 必填里面再按照父子关系分组成一个map
	 *
	 * @param response
	 * @param labelList
	 */
	private void dealLabelList(ResponseLabelInfo response, List<Label> labelList) {
		List<Label> level1Label = getLabelByLevel(labelList, 1);
		List<Label> level2Label = getLabelByLevel(labelList, 2);

		Map<Long, Collection<Label>> map = Multimaps.index(level2Label, new Function<Label, Long>() {
			public Long apply(Label from) {
				return from.getParentId();
			}
		}).asMap();

		Function<Label, LabelDto> changeFunction = new Function<Label, LabelDto>() {
			public LabelDto apply(Label input) {
				LabelDto labelDto = new LabelDto();
				labelDto.setId(String.valueOf(input.getId()));
				labelDto.setLabelName(input.getLabelName());
				return labelDto;
			}
		};

		List<Label> choosedLabels = new ArrayList<Label>();

		Map<String, List<LabelDto>> requiredLabels = new HashMap<String, List<LabelDto>>();
		for (Label label : level1Label) {
			if (MemberConstants.CHOOSED_LABEL.equals(label.getLabelType())) {
				choosedLabels.add(label);
			} else {
				Collection<Label> collection = map.get(label.getId());
				if (CollectionUtils.isEmpty(collection)) {
					continue;
				}
				List<LabelDto> requiredLabelDtos = new ArrayList<LabelDto>();
				for (Label lable : collection) {
					requiredLabelDtos.add(changeFunction.apply(lable));
				}
				requiredLabels.put(label.getLabelName(), requiredLabelDtos);
			}
		}

		List<LabelDto> choosedLabelDtos = Lists.transform(choosedLabels, changeFunction);
		response.setReqiredLabels(requiredLabels);
		response.setChooseLabels(choosedLabelDtos);
	}

	/**
	 * 根据parentId是否为空，分组成一级和二级标签
	 *
	 */
	private List<Label> getLabelByLevel(List<Label> labelList, final int level) {
		Predicate<Label> predicate = new Predicate<Label>() {
			public boolean apply(Label input) {
				if (level == 1) {
					return input.getParentId() == null;
				}
				return input.getParentId() != null;
			}
		};
		return FluentIterable.from(labelList).filter(predicate).toList();
	}

	@Override
	public BaseResponse commitLabelInfo(ReqLabel reqLabel) {
		LOGGER.debug("提交会员标签信息:{}", reqLabel);
		BaseResponse response = new BaseResponse();
		response.setRetFlag(ReturnMsg.FAIL);
		if (!checkParam(reqLabel)) {
			response.setErrorCode(ErrorCodeConstants.ERR_MEM_0053);
			response.setErrorMessage(ErrorCodeConstants.ERR_MAP.get(ErrorCodeConstants.ERR_MEM_0053));
			return response;
		}
		MemCustomerDetailResponse customerDetailVo = new MemCustomerDetailResponse();
		// 根据custNo,source,店员 查询 客户，如果查到，则更新，如果未查询到，则新增
		String custNo = reqLabel.getCustNo();
		String employeeId = reqLabel.getStaffId();
		String source = reqLabel.getSource();
		// 邱刚说目前都是收集新会员，所以手机号不会为空
		String mobile = reqLabel.getMobile();

		// 手机号，加密，因为service方法里会再解密，为了配和app
		mobile = AESUtils.encrypt(mobile, ConfigConstants.AES_KEY);
		customerDetailVo.setCustNo(custNo);
		customerDetailVo.setCustName(reqLabel.getCustName());
		customerDetailVo.setMobile(mobile);
		customerDetailVo.setLabelIds(reqLabel.getLabelIds());
		customerDetailVo.setSource(source);

		// 查询库中当前来源是否已有此人
		CustomerDetail customDetail = activityService.queryCustomerDetailByParams(custNo, employeeId, source);
		if (customDetail == null) { // 新增
			customerDetailVo.setIsUpdate(0);
		} else { // 更新--此渠道过来的更新操作应该比较少
			customerDetailVo.setIsUpdate(1);
			customerDetailVo.setDetailId(customDetail.getId());
			MemCustomer customer = activityService.queryCustomerByParams(custNo, employeeId);
			if (customer != null) {
				customerDetailVo.setCustId(customer.getId());
			} else {
				LOGGER.error("查询有会员详情数据，但是未出现到会员数据，数据异常。custDetailId:{},custNo:{}", customDetail.getId(), custNo);
				response.setErrorCode(ErrorCodeConstants.ERR_MEM_0054);
				response.setErrorMessage("客户资料异常。");
				return response;
			}
		}
		// 入库
		ReturnMsg<MemCustomerDetailResponse> returnMsg = activityService.saveOrUpdateCustomer(customerDetailVo, employeeId);
		if (ReturnMsg.FAIL.equals(returnMsg.getRetFlag())) {
			response.setErrorCode(ErrorCodeConstants.ERR_MEM_0054);
			response.setErrorMessage(returnMsg.getErrorMessage());
			return response;
		}
		response.setRetFlag(ReturnMsg.SUCCESS);
		return response;
	}

	private boolean checkParam(ReqLabel reqLabel) {
		// 参数非空项为空了
		if (reqLabel == null || reqLabel.getCustNo() == null || reqLabel.getCustName() == null || reqLabel.getLabelIds() == null || reqLabel.getSource() == null || reqLabel.getStaffId() == null
				|| reqLabel.getMobile() == null) {
			return false;
		}
		return true;
	}

}
